package com.cocotingo.snail.template;

import java.awt.Color;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.cocotingo.snail.GraphicsX;
import com.cocotingo.snail.KeyEvent;
import com.cocotingo.snail.MouseEvent;
import com.cocotingo.snail.MouseWheelEvent;
import com.cocotingo.snail.Vector;
import com.cocotingo.snail.View;

public class TemplateView extends View {
	
	private static class HandlerBundle {
		private final Map<String, List<EventHandler>> handlerMap;
		HandlerBundle() {
			handlerMap = new HashMap<String, List<EventHandler>>(2);
		}
		boolean addHandler(String eventName, EventHandler handler) {
			List<EventHandler> list = handlerMap.get(eventName);
			if (list == null) {
				list = new LinkedList<EventHandler>();
				handlerMap.put(eventName, list);
			}
			if (!list.contains(handler)) {
				list.add(handler);
				return true;
			} else {
				return false;
			}
		}
		boolean removeHandler(String eventName, EventHandler handler) {
			List<EventHandler> list = handlerMap.get(eventName);
			if (list != null && list.contains(handler)) {
				return list.remove(handler);
			} else {
				return false;
			}
		}
		void fireEvent(TemplateView sender, String eventName, Object arg) {
			List<EventHandler> list = handlerMap.get(eventName);
			if (list != null) {
				for (EventHandler eventHandler : list) {
					eventHandler.handle(sender, eventName, arg);
				}
			}
		}
	}
	
	public static final String ALPHA_CHANGED = "alphaChanged";
	public static final String BACKGROUND_COLOR_CHANGED = "backgroundColorChanged";
	public static final String HIDDEN_CHANGED = "hiddenChanged";
	public static final String POSITION_CHANGED = "positionChanged";
	public static final String SIZE_CHANGED = "sizeChanged";
	public static final String GOT_KEYBOARD_FOCUS = "gotKeyboardFocus";
	public static final String LOST_KEYBOARD_FOCUS = "lostKeyboardFocus";
	public static final String MOUSE_ENTERED = "mouseEntered";
	public static final String MOUSE_EXITED = "mouseExited";
	public static final String PRE_KEY_PRESSED = "preKeyPressed";
	public static final String PRE_KEY_RELEASED = "preKeyReleased";
	public static final String PRE_KEY_TYPED = "preKeyTyped";
	public static final String PRE_MOUSE_PRESSED = "preMousePressed";
	public static final String PRE_MOUSE_RELEASED = "preMouseReleased";
	public static final String PRE_MOUSE_CLICKED = "preMouseClicked";
	public static final String PRE_MOUSE_MOVED = "preMouseMoved";
	public static final String PRE_MOUSE_DRAGGED = "preMouseDragged";
	public static final String PRE_MOUSE_WHEEL_MOVED = "preMouseWheelMoved";
	public static final String POST_KEY_PRESSED = "postKeyPressed";
	public static final String POST_KEY_RELEASED = "postKeyReleased";
	public static final String POST_KEY_TYPED = "postKeyTyped";
	public static final String POST_MOUSE_PRESSED = "postMousePressed";
	public static final String POST_MOUSE_RELEASED = "postMouseReleased";
	public static final String POST_MOUSE_CLICKED = "postMouseClicked";
	public static final String POST_MOUSE_MOVED = "postMouseMoved";
	public static final String POST_MOUSE_DRAGGED = "postMouseDragged";
	public static final String POST_MOUSE_WHEEL_MOVED = "postMouseWheelMoved";
	public static final String REPAINT_VIEW = "repaintView";
	public static final String SUBVIEW_ADDED = "subviewAdded";
	public static final String SUBVIEW_REMOVED = "subviewRemoved";
	public static final String SUBVIEW_INDEX_CHANGED = "subviewIndexChanged";
	public static final String LAYOUT = "layout";
	
	private HandlerBundle handlerBundle;
	private int tag;

	public TemplateView() {
		super();
		handlerBundle = null;
		tag = 0;
	}
	
	protected void madeFromTemplate(TemplateLoader loader) {
	}
	
	public void layout() {
		fireEvent(LAYOUT);
	}
	
	public int getPreferredWidth() {
		throw new UnsupportedOperationException();
	}
	
	public int getPreferredHeight() {
		throw new UnsupportedOperationException();
	}
	
	public final Vector getPreferredSize() {
		return new Vector(getPreferredWidth(), getPreferredHeight());
	}

	public int getTag() {
		return tag;
	}
	
	public void setTag(int tag) {
		this.tag = tag;
	}
	
	public TemplateView getTaggedSubview(int tag) {
		for (View view : this) {
			if ((view instanceof TemplateView) && ((TemplateView) view).tag == tag)
			return (TemplateView) view;
		}
		return null;
	}
	
	public TemplateView getTaggedSubviewDeeply(int tag) {
		return getTaggedSubviewDeeply(this, tag);
	}
	
	private static TemplateView getTaggedSubviewDeeply(TemplateView target, int tag) {
		TemplateView rst = target.getTaggedSubview(tag);
		if (rst != null) return rst;
		else {
			for (View view : target) {
				if (view instanceof TemplateView) {
					return getTaggedSubviewDeeply((TemplateView) view, tag);
				}
			}
			return null;
		}
	}
	
	public boolean addEventHandler(String eventName, EventHandler handler) {
		if (handlerBundle == null) {
			handlerBundle = new HandlerBundle();
		}
		return handlerBundle.addHandler(eventName, handler);
	}

	public boolean removeEventHandler(String eventName, EventHandler handler) {
		if (handlerBundle != null) {
			return handlerBundle.removeHandler(eventName, handler);
		} else {
			return false;
		}
	}

	public final void fireEvent(String eventName) {
		if (handlerBundle != null) handlerBundle.fireEvent(this, eventName, null);
	}

	public final void fireEventWithArgument(String eventName, Object arg) {
		if (handlerBundle != null) handlerBundle.fireEvent(this, eventName, arg);
	}

	@Override
	public void setAlpha(float alpha) {
		if (getAlpha() != alpha) {
			super.setAlpha(alpha);
			fireEvent(ALPHA_CHANGED);
		}
	}

	@Override
	public void setBackgroundColor(Color backgroundColor) {
		if (getBackgroundColor() != backgroundColor) {
			super.setBackgroundColor(backgroundColor);
			fireEvent(BACKGROUND_COLOR_CHANGED);
		}
	}

	@Override
	public void setHidden(boolean hidden) {
		if (isHidden() != hidden) {
			super.setHidden(hidden);
			fireEvent(HIDDEN_CHANGED);
			if (!hidden) layout();
		}
	}

	@Override
	public void setPosition(int left, int top) {
		if (getLeft() != left || getTop() != top) {
			super.setPosition(left, top);
			fireEvent(POSITION_CHANGED);
		}
	}

	@Override
	public void setSize(int width, int height) {
		if (getWidth() != width || getHeight() != height) {
			super.setSize(width, height);
			fireEvent(SIZE_CHANGED);
			if (!isHidden()) layout();
		}
	}

	@Override
	public void setSubviewIndex(View view, int targetIndex) {
		if (view.getIndex() != targetIndex) {
			super.setSubviewIndex(view, targetIndex);
			fireEventWithArgument(SUBVIEW_INDEX_CHANGED, view);
		}
	}

	@Override
	protected void gotKeyboardFocus() {
		fireEvent(GOT_KEYBOARD_FOCUS);
	}

	@Override
	protected void lostKeyboardFocus() {
		fireEvent(LOST_KEYBOARD_FOCUS);
	}

	@Override
	protected void repaintView(GraphicsX g) {
		fireEventWithArgument(REPAINT_VIEW, g);
	}

	@Override
	protected void subviewAdded(View subview) {
		super.subviewAdded(subview);
		fireEventWithArgument(SUBVIEW_ADDED, subview);
	}

	@Override
	protected void subviewRemoved(View subview) {
		super.subviewRemoved(subview);
		fireEventWithArgument(SUBVIEW_REMOVED, subview);
	}

	@Override
	protected void mouseEntered() {
		fireEvent(MOUSE_ENTERED);
	}

	@Override
	protected void mouseExited() {
		fireEvent(MOUSE_EXITED);
	}

	@Override
	protected void preKeyPressed(KeyEvent e) {
		fireEventWithArgument(PRE_KEY_PRESSED, e);
	}

	@Override
	protected void preKeyReleased(KeyEvent e) {
		fireEventWithArgument(PRE_KEY_RELEASED, e);
	}

	@Override
	protected void preKeyTyped(KeyEvent e) {
		fireEventWithArgument(PRE_KEY_TYPED, e);
	}

	@Override
	protected void preMouseClicked(MouseEvent e) {
		fireEventWithArgument(PRE_MOUSE_CLICKED, e);
	}

	@Override
	protected void preMouseDragged(MouseEvent e) {
		fireEventWithArgument(PRE_MOUSE_DRAGGED, e);
	}

	@Override
	protected void preMouseMoved(MouseEvent e) {
		fireEventWithArgument(PRE_MOUSE_MOVED, e);
	}

	@Override
	protected void preMousePressed(MouseEvent e) {
		fireEventWithArgument(PRE_MOUSE_PRESSED, e);
	}

	@Override
	protected void preMouseReleased(MouseEvent e) {
		fireEventWithArgument(PRE_MOUSE_RELEASED, e);
	}

	@Override
	protected void preMouseWheelMoved(MouseWheelEvent e) {
		fireEventWithArgument(PRE_MOUSE_WHEEL_MOVED, e);
	}

	@Override
	protected void postKeyPressed(KeyEvent e) {
		fireEventWithArgument(POST_KEY_PRESSED, e);
	}

	@Override
	protected void postKeyReleased(KeyEvent e) {
		fireEventWithArgument(POST_KEY_RELEASED, e);
	}

	@Override
	protected void postKeyTyped(KeyEvent e) {
		fireEventWithArgument(POST_KEY_TYPED, e);
	}

	@Override
	protected void postMouseClicked(MouseEvent e) {
		fireEventWithArgument(POST_MOUSE_CLICKED, e);
	}

	@Override
	protected void postMouseDragged(MouseEvent e) {
		fireEventWithArgument(POST_MOUSE_DRAGGED, e);
	}

	@Override
	protected void postMouseMoved(MouseEvent e) {
		fireEventWithArgument(POST_MOUSE_MOVED, e);
	}

	@Override
	protected void postMousePressed(MouseEvent e) {
		fireEventWithArgument(POST_MOUSE_PRESSED, e);
	}

	@Override
	protected void postMouseReleased(MouseEvent e) {
		fireEventWithArgument(POST_MOUSE_RELEASED, e);
	}

	@Override
	protected void postMouseWheelMoved(MouseWheelEvent e) {
		fireEventWithArgument(POST_MOUSE_WHEEL_MOVED, e);
	}

}
